package cn.iocoder.yudao.module.member.service.user;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.*;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.member.controller.admin.user.enums.TeamAuditEnum;
import cn.iocoder.yudao.module.member.controller.admin.user.vo.*;
import cn.iocoder.yudao.module.member.controller.app.user.vo.*;
import cn.iocoder.yudao.module.member.convert.auth.AuthConvert;
import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
import cn.iocoder.yudao.module.member.mq.producer.user.MemberUserProducer;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
import cn.iocoder.yudao.module.system.api.social.SocialClientApi;
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxPhoneNumberInfoRespDTO;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import cn.iocoder.yudao.module.wine.api.BusinessUserApi;
import cn.iocoder.yudao.module.wine.api.BusinessUserLogApi;
import cn.iocoder.yudao.module.wine.api.WineConfigApi;
import cn.iocoder.yudao.module.wine.api.dto.BusinessUserDTO;
import cn.iocoder.yudao.module.wine.api.dto.BusinessUserLogDTO;
import cn.iocoder.yudao.module.wine.api.dto.WineConfigDTO;
import com.google.common.annotations.VisibleForTesting;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*;
import static net.sf.jsqlparser.util.validation.metadata.NamedObject.user;

/**
 * 会员 User Service 实现类
 *
 * @author 商城源码
 */
@Service
@Valid
@Slf4j
public class MemberUserServiceImpl implements MemberUserService {

    @Resource
    private MemberUserMapper memberUserMapper;

    @Resource
    private SmsCodeApi smsCodeApi;

    @Resource
    private SocialClientApi socialClientApi;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private MemberUserProducer memberUserProducer;

    @Resource
    private BusinessUserLogApi businessUserLogApi;

    @Resource
    private DictDataApi dataApi;

    @Resource
    private WineConfigApi wineConfigApi;

    @Resource
    private BusinessUserApi businessUserApi;

    @Override
    public MemberUserDO getUserByMobile(String mobile) {
        return memberUserMapper.selectByMobile(mobile);
    }

    @Override
    public List<MemberUserDO> getUserListByNickname(String nickname) {
        return memberUserMapper.selectListByNicknameLike(nickname);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MemberUserDO createUserIfAbsent(String mobile, String registerIp, Integer terminal) {
        // 用户已经存在
        MemberUserDO user = memberUserMapper.selectByMobile(mobile);
        if (user != null) {
            return user;
        }
        // 用户不存在，则进行创建
        return createUser(mobile, null, null, registerIp, terminal);
    }

    /**
     * 管理员 创建用户
     * @param createReqVO 用户信息
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createUser(MemberUserSaveReqVO createReqVO) {
        // 校验正确性
        //validateUserForCreateOrUpdate(null,
        //        createReqVO.getUsername(),
        //        createReqVO.getMobile(),
        //        createReqVO.getEmail(),
        //        createReqVO.getDeptId(),
        //        createReqVO.getPostIds());
        // 插入用户
        MemberUserDO user = BeanUtils.toBean(createReqVO, MemberUserDO.class);

        user.setRegisterTerminal(1);
        user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
        user.setPassword(encodePassword(createReqVO.getPassword())); // 加密密码

        memberUserMapper.insert(user);

        return user.getId();
    }

    /**
     * 后台添加团长用户
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public MemberUserDO createTeamUser(String mobile, String nickname, String name, String password, Integer areaId,
                                       String avatar, Integer sex, String mark,Integer teamAudit) {
        MemberUserDO memberUserDO = memberUserMapper.selectByMobile(mobile);
        if (memberUserDO == null) {
            // 获取IP
            String userIp = getClientIP();

            // 插入用户
            MemberUserDO user = new MemberUserDO();

            user.setAvatar(avatar);
            user.setSex(sex);
            user.setMobile(mobile);
            user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
            user.setPassword(encodePassword(password)); // 加密密码
            user.setRegisterIp(userIp).setRegisterTerminal(TerminalEnum.ADMIN_INSERT.getTerminal());
            user.setNickname(nickname); // 基础信息
            user.setAreaId(areaId);//区域ID
            user.setIsTeam(1); //1 团长 2 非团长
            user.setTeamAudit(teamAudit); //0未申请 1申请中 2已通过 3已拒绝
            user.setIsBusiness(2);//1 商家 2 非商家
            user.setName(name);
            user.setWechatNumber("");
            user.setMoneyReceivingCode("");
            user.setMark(mark);
            if (StrUtil.isEmpty(nickname)) {
                user.setNickname(name);
            }
            //默认赋值
            user.setGroupId(1L);
            user.setLevelId(0L);

            LocalDate now = LocalDate.now();
            Integer profitYear = 1;
            //如果开启有收益时间，则设置过期时间
            //如果开启免费，则增加免费使用时间
            WineConfigDTO wineConfigDTO = wineConfigApi.getWineConfigInfo();
            if(wineConfigDTO!=null && wineConfigDTO.getIsOpenMonth()>0 && wineConfigDTO.getFreeMonth()>0) {
                profitYear = wineConfigDTO.getProfitYear();
                LocalDate expirationTime = now.plusMonths(wineConfigDTO.getFreeMonth());
                user.setTeamExpirationTime(expirationTime.atStartOfDay());
            }
            //审核则增加时间
            if(Objects.equals(teamAudit, TeamAuditEnum.PASSED.getCode())) {
                LocalDate overTime = now.plusYears(profitYear);
                user.setTeamOpenTime(now.atStartOfDay());
                user.setTeamOverTime(overTime.atStartOfDay());
            }

            memberUserMapper.insert(user);

            BusinessUserLogDTO businessUserLogDTO = new BusinessUserLogDTO();
            businessUserLogDTO.setAppUserId(user.getId());
            businessUserLogDTO.setUserId(user.getId());
            businessUserLogDTO.setContent("后台添加团长中...");

            businessUserLogDTO.setBeforeStatus("未添加");
            businessUserLogDTO.setAfterStatus("已添加");
            businessUserLogApi.addLog(businessUserLogDTO);

            // 发送 MQ 消息：用户创建
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    memberUserProducer.sendUserCreateMessage(user.getId());
                }
            });
            return user;
        }
        return  null;
    }


    /**
     * 创建用户
     *  目的：三方登录时，如果未绑定用户时，自动创建对应用户
     * @param nickname   昵称
     * @param avtar      头像
     * @param registerIp 注册 IP
     * @param terminal   终端 {@link TerminalEnum}
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public MemberUserDO createUser(String nickname, String avtar, String registerIp, Integer terminal) {
        return createUser(null, nickname, avtar, registerIp, terminal);
    }



    private MemberUserDO createUser(String mobile, String nickname, String avtar, String registerIp, Integer terminal) {
        // 生成密码
        String password = IdUtil.fastSimpleUUID();
        // 插入用户
        MemberUserDO user = new MemberUserDO();
        user.setMobile(mobile);
        user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
        user.setPassword(encodePassword(password)); // 加密密码
        user.setRegisterIp(registerIp)
                .setRegisterTerminal(terminal);
        user.setNickname(nickname).setAvatar(avtar); // 基础信息
        if (StrUtil.isEmpty(nickname)) {
            // 昵称为空时，随机一个名字，避免一些依赖 nickname 的逻辑报错，或者有点丑。例如说，短信发送有昵称时~
            user.setNickname("用户" + RandomUtil.randomNumbers(6));
        }
        memberUserMapper.insert(user);

        // 发送 MQ 消息：用户创建
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {
                memberUserProducer.sendUserCreateMessage(user.getId());
            }

        });
        return user;
    }

    /**
     * 商家入驻时创建用户
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public MemberUserDO createUserByBusiness(Long id, String mobile, String nickname, String name,
                                             String registerIp, Integer terminal, String password, Integer areaId) {
        MemberUserDO memberUserDO = memberUserMapper.selectByMobile(mobile);
        if (memberUserDO != null) {
            //确保前端有传ID参数，没传表示注册，注册不能重复
            if (id==null || id <= 0) {
                throw exception(AUTH_MOBILE_USED);
            }
            memberUserDO.setMobile(mobile);
            memberUserDO.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
            memberUserDO.setPassword(encodePassword(password)); // 加密密码
            memberUserDO.setRegisterIp(registerIp).setRegisterTerminal(terminal);
            memberUserDO.setNickname(nickname); // 基础信息
            memberUserDO.setAreaId(areaId);//区域Id
            memberUserDO.setIsBusiness(1); //1 商家 2 非商家
            memberUserDO.setName(name);
            if (StrUtil.isEmpty(nickname)) {
                // 昵称为空时，随机一个名字，避免一些依赖 nickname 的逻辑报错，或者有点丑。例如说，短信发送有昵称时~
                memberUserDO.setNickname(name);
            }

            // 发送 MQ 消息：用户创建
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    memberUserProducer.sendUserCreateMessage(memberUserDO.getId());
                }
            });
            return memberUserDO;

        } else {
            // 生成密码
            // 插入用户
            MemberUserDO user = new MemberUserDO();
            user.setMobile(mobile);
            user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
            user.setPassword(encodePassword(password)); // 加密密码
            user.setRegisterIp(registerIp).setRegisterTerminal(terminal);
            user.setNickname(nickname); // 基础信息
            user.setAreaId(areaId);//区域Id
            user.setIsTeam(2); //1 团长 2 非团长
            user.setTeamAudit(0); //0未申请 1申请中 2已通过 3已拒绝
            user.setIsBusiness(1); //1 商家 2 非商家
            user.setName(name);
            user.setAudit(2);//默认发布的信息无需审核
            if (StrUtil.isEmpty(nickname)) {
                // 昵称为空时，随机一个名字，避免一些依赖 nickname 的逻辑报错，或者有点丑。例如说，短信发送有昵称时~
                user.setNickname(name);
            }
            user.setGroupId(1L);
            user.setLevelId(0L);
            memberUserMapper.insert(user);
            //创建分销账户

            // 发送 MQ 消息：用户创建
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    memberUserProducer.sendUserCreateMessage(user.getId());
                }
            });

            return user;
        }
    }


    /**
     * 个人团长入驻时创建用户
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public MemberUserDO createUserByBusinessTeam(Long id, String mobile, String nickname, String name,
                                                 String registerIp, Integer terminal, String password, Integer areaId,
                                                 String wechatNumber, String moneyReceivingCode, String mark) {

        MemberUserDO memberUserDO = memberUserMapper.selectByMobile(mobile);

        if (memberUserDO != null) {
            //确保前端有传ID参数，没传表示注册，注册不能重复
            if (id==null || id <= 0) {
                throw exception(AUTH_MOBILE_USED);
            }
            memberUserDO.setMobile(mobile);
            memberUserDO.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
            memberUserDO.setPassword(encodePassword(password)); // 加密密码
            memberUserDO.setRegisterIp(registerIp).setRegisterTerminal(terminal);
            memberUserDO.setNickname(nickname); // 基础信息
            memberUserDO.setAreaId(areaId);//区域ID
            memberUserDO.setIsTeam(1); //1 团长 2 非团长
            memberUserDO.setTeamAudit(1); //0未申请 1申请中 2已通过 3已拒绝
            memberUserDO.setName(name);
            memberUserDO.setWechatNumber(wechatNumber);
            memberUserDO.setMoneyReceivingCode(moneyReceivingCode);
            memberUserDO.setMark(mark);

            //如果开启免费，则增加免费使用时间
            WineConfigDTO wineConfigDTO = wineConfigApi.getWineConfigInfo();
            if(wineConfigDTO!=null && wineConfigDTO.getIsOpenMonth()>0 && wineConfigDTO.getFreeMonth()>0) {
                LocalDate now = LocalDate.now();
                LocalDate expirationTime = now.plusMonths(wineConfigDTO.getFreeMonth());
                memberUserDO.setTeamExpirationTime(expirationTime.atStartOfDay());
            }
            memberUserMapper.updateById(memberUserDO);

            BusinessUserLogDTO businessUserLogDTO = new BusinessUserLogDTO();
            businessUserLogDTO.setAppUserId(memberUserDO.getId());
            businessUserLogDTO.setUserId(memberUserDO.getId());
            businessUserLogDTO.setContent("团长申请中...");

            businessUserLogDTO.setBeforeStatus("未申请");
            businessUserLogDTO.setAfterStatus("申请中");

            businessUserLogApi.addLog(businessUserLogDTO);

            // 发送 MQ 消息：用户创建
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    memberUserProducer.sendUserCreateMessage(memberUserDO.getId());
                }
            });

            return memberUserDO;

        } else {
            // 生成密码
            // 插入用户
            MemberUserDO user = new MemberUserDO();
            user.setMobile(mobile);
            user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
            user.setPassword(encodePassword(password)); // 加密密码
            user.setRegisterIp(registerIp).setRegisterTerminal(terminal);
            user.setNickname(nickname); // 基础信息
            user.setAreaId(areaId);//区域ID
            user.setIsTeam(1); //1 团长 2 非团长
            user.setTeamAudit(1); //0未申请 1申请中 2已通过 3已拒绝
            user.setIsBusiness(2);//1 商家 2 非商家
            user.setName(name);
            user.setWechatNumber(wechatNumber);
            user.setMoneyReceivingCode(moneyReceivingCode);
            user.setMark(mark);
            if (StrUtil.isEmpty(nickname)) {
                // 昵称为空时，随机一个名字，避免一些依赖 nickname 的逻辑报错，或者有点丑。例如说，短信发送有昵称时~
                user.setNickname(name);
//                user.setNickname("用户" + RandomUtil.randomNumbers(6));
            }
            memberUserMapper.insert(user);

            BusinessUserLogDTO businessUserLogDTO = new BusinessUserLogDTO();
            businessUserLogDTO.setAppUserId(user.getId());
            businessUserLogDTO.setUserId(user.getId());
            businessUserLogDTO.setContent("用户申请团长中...");

            businessUserLogDTO.setBeforeStatus("未申请");
            businessUserLogDTO.setAfterStatus("申请中");
            businessUserLogApi.addLog(businessUserLogDTO);

            // 发送 MQ 消息：用户创建
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    memberUserProducer.sendUserCreateMessage(user.getId());
                }
            });

            return user;
        }
    }

    /**
     * 商家申请团长
     * @param mobile
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public MemberUserDO createUserByBusinessTeamSimple(String mobile) {

        MemberUserDO memberUserDO = memberUserMapper.selectByMobile(mobile);
        if(memberUserDO!=null){
            //参数赋值
            memberUserDO.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
            memberUserDO.setIsTeam(1); //1 团长 2 非团长
            memberUserDO.setTeamAudit(1); //0未申请 1申请中 2已通过 3已拒绝
            memberUserMapper.updateById(memberUserDO);

            //写日志
            BusinessUserLogDTO businessUserLogDTO = new BusinessUserLogDTO();
            businessUserLogDTO.setAppUserId(memberUserDO.getId());
            businessUserLogDTO.setUserId(memberUserDO.getId());
            businessUserLogDTO.setContent("商家申请团长中...");
            businessUserLogDTO.setBeforeStatus("未申请");
            businessUserLogDTO.setAfterStatus("申请中");

            businessUserLogApi.addLog(businessUserLogDTO);
        }

        return memberUserDO;
    }

    @Override
    public void updateUserLogin(Long id, String loginIp) {
        memberUserMapper.updateById(new MemberUserDO().setId(id)
                .setLoginIp(loginIp).setLoginDate(LocalDateTime.now()));
    }

    @Override
    public MemberUserDO getUser(Long id) {
        return memberUserMapper.selectById(id);
    }

    @Override
    public List<MemberUserDO> getUserList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return ListUtil.empty();
        }
        return memberUserMapper.selectBatchIds(ids);
    }

    @Override
    public void updateUser(Long userId, AppMemberUserUpdateReqVO reqVO) {
        MemberUserDO updateObj = BeanUtils.toBean(reqVO, MemberUserDO.class).setId(userId);
        memberUserMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUserMobile(Long userId, AppMemberUserUpdateMobileReqVO reqVO) {
        // 1.1 检测用户是否存在
        MemberUserDO user = validateUserExists(userId);
        // 1.2 校验新手机是否已经被绑定
        validateMobileUnique(null, reqVO.getMobile());

        // 2.1 校验旧手机和旧验证码
        // 补充说明：从安全性来说，老手机也校验 oldCode 验证码会更安全。但是由于 uni-app 商城界面暂时没做，所以这里不强制校验
        if (StrUtil.isNotEmpty(reqVO.getOldCode())) {
            smsCodeApi.useSmsCode(new SmsCodeUseReqDTO().setMobile(user.getMobile()).setCode(reqVO.getOldCode())
                    .setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene()).setUsedIp(getClientIP()));
        }
        // 2.2 使用新验证码
        smsCodeApi.useSmsCode(new SmsCodeUseReqDTO().setMobile(reqVO.getMobile()).setCode(reqVO.getCode())
                .setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene()).setUsedIp(getClientIP()));

        // 3. 更新用户手机
        memberUserMapper.updateById(MemberUserDO.builder().id(userId).mobile(reqVO.getMobile()).build());
    }

    @Override
    public void updateUserMobileByWeixin(Long userId, AppMemberUserUpdateMobileByWeixinReqVO reqVO) {
        // 1.1 获得对应的手机号信息
        SocialWxPhoneNumberInfoRespDTO phoneNumberInfo = socialClientApi.getWxMaPhoneNumberInfo(
                UserTypeEnum.MEMBER.getValue(), reqVO.getCode());
        Assert.notNull(phoneNumberInfo, "获得手机信息失败，结果为空");
        // 1.2 校验新手机是否已经被绑定
        validateMobileUnique(userId, phoneNumberInfo.getPhoneNumber());

        // 2. 更新用户手机
        memberUserMapper.updateById(MemberUserDO.builder().id(userId).mobile(phoneNumberInfo.getPhoneNumber()).build());
    }

    @Override
    public void updateUserPassword(Long userId, AppMemberUserUpdatePasswordReqVO reqVO) {
        // 检测用户是否存在
        MemberUserDO user = validateUserExists(userId);
        // 校验验证码
        smsCodeApi.useSmsCode(new SmsCodeUseReqDTO().setMobile(user.getMobile()).setCode(reqVO.getCode())
                .setScene(SmsSceneEnum.MEMBER_UPDATE_PASSWORD.getScene()).setUsedIp(getClientIP()));

        // 更新用户密码
        memberUserMapper.updateById(MemberUserDO.builder().id(userId)
                .password(passwordEncoder.encode(reqVO.getPassword())).build());
    }

    @Override
    public void resetUserPassword(AppMemberUserResetPasswordReqVO reqVO) {
        // 检验用户是否存在
        MemberUserDO user = validateUserExists(reqVO.getMobile());

        // 使用验证码
        smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.MEMBER_RESET_PASSWORD, getClientIP()));

        // 更新密码
        memberUserMapper.updateById(MemberUserDO.builder().id(user.getId())
                .password(passwordEncoder.encode(reqVO.getPassword())).build());
    }

    private MemberUserDO validateUserExists(String mobile) {
        MemberUserDO user = memberUserMapper.selectByMobile(mobile);
        if (user == null) {
            throw exception(USER_MOBILE_NOT_EXISTS);
        }
        return user;
    }

    @Override
    public boolean isPasswordMatch(String rawPassword, String encodedPassword) {
        return passwordEncoder.matches(rawPassword, encodedPassword);
    }

    /**
     * 对密码进行加密
     *
     * @param password 密码
     * @return 加密后的密码
     */
    private String encodePassword(String password) {
        return passwordEncoder.encode(password);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUser(MemberUserUpdateReqVO updateReqVO) {
        // 校验存在
        validateUserExists(updateReqVO.getId());
        // 校验手机唯一
        validateMobileUnique(updateReqVO.getId(), updateReqVO.getMobile());
        // 更新
        MemberUserDO user = memberUserMapper.selectById(updateReqVO.getId());
        if(updateReqVO.getPassword()!=null && StrUtil.isNotEmpty(updateReqVO.getPassword())) {
            updateReqVO.setPassword(encodePassword(updateReqVO.getPassword()));
        }
        else{
            updateReqVO.setPassword(user.getPassword());
        }
        MemberUserDO updateObj = MemberUserConvert.INSTANCE.convert(updateReqVO);
        memberUserMapper.updateById(updateObj);
    }

    @VisibleForTesting
    MemberUserDO validateUserExists(Long id) {
        if (id == null) {
            return null;
        }
        MemberUserDO user = memberUserMapper.selectById(id);
        if (user == null) {
            throw exception(USER_NOT_EXISTS);
        }
        return user;
    }

    @VisibleForTesting
    void validateMobileUnique(Long id, String mobile) {
        if (StrUtil.isBlank(mobile)) {
            return;
        }
        MemberUserDO user = memberUserMapper.selectByMobile(mobile);
        if (user == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的用户
        if (id == null) {
            throw exception(USER_MOBILE_USED, mobile);
        }
        if (!user.getId().equals(id)) {
            throw exception(USER_MOBILE_USED, mobile);
        }
    }

    /**
     * 【管理员】获得会员用户分页
     * @param pageReqVO 分页查询
     * @return
     */
    @Override
    public PageResult<MemberUserDO> getUserPage(MemberUserPageReqVO pageReqVO) {
        return memberUserMapper.selectPage(pageReqVO);
    }

    /**
     * 【管理员】获得团长用户分页
     * @param pageReqVO 分页查询
     * @return
     */
    @Override
    public PageResult<MemberUserDO> getTeamUserPage(MemberUserPageReqVO pageReqVO) {
        return memberUserMapper.selectTeamUserPage(pageReqVO);
    }
    /**
     * 【管理员】获得商家用户分页
     * @param pageReqVO 分页查询
     * @return
     */
    @Override
    public PageResult<MemberUserDO> getBusinessUserPage(MemberUserPageReqVO pageReqVO) {
        return memberUserMapper.selectBusinessUserPage(pageReqVO);
    }

    @Override
    public void updateUserLevel(Long id, Long levelId, Integer experience) {
        // 0 代表无等级：防止UpdateById时，会被过滤掉的问题
        levelId = ObjectUtil.defaultIfNull(levelId, 0L);
        memberUserMapper.updateById(new MemberUserDO()
                .setId(id)
                .setLevelId(levelId).setExperience(experience)
        );
    }

    @Override
    public Long getUserCountByGroupId(Long groupId) {
        return memberUserMapper.selectCountByGroupId(groupId);
    }

    @Override
    public Long getUserCountByLevelId(Long levelId) {
        return memberUserMapper.selectCountByLevelId(levelId);
    }

    @Override
    public Long getUserCountByTagId(Long tagId) {
        return memberUserMapper.selectCountByTagId(tagId);
    }

    @Override
    public boolean updateUserPoint(Long id, Integer point) {
        if (point > 0) {
            memberUserMapper.updatePointIncr(id, point);
        } else if (point < 0) {
            return memberUserMapper.updatePointDecr(id, point) > 0;
        }
        return true;
    }

    @Override
    public Integer updateAppPassword(MemberUserDO user) {
        return memberUserMapper.updateById(user);
    }

    /**
     * 审核团长
     * @param updateReqVO
     */
    @Override
    public void updateUserAudit(MemberUserUpdateAuditReqVO updateReqVO) {
        //团长审核字典
        List<DictDataRespDTO> teamStatus = dataApi.getDictDataList("team_audit");
        MemberUserDO memberUserDO = validateUserExists(updateReqVO.getId());
        if (!memberUserDO.getTeamAudit().equals(updateReqVO.getTeamAudit())) {
            BusinessUserLogDTO businessUserLogDTO = new BusinessUserLogDTO();
            for (int i = 0; i < teamStatus.size(); i++) {
                DictDataRespDTO dictDataRespDTO = teamStatus.get(i);
                if (dictDataRespDTO.getValue().equals(String.valueOf(updateReqVO.getTeamAudit()))) {
                    businessUserLogDTO.setAfterStatus(dictDataRespDTO.getLabel());
                }
                if (dictDataRespDTO.getValue().equals(String.valueOf(memberUserDO.getTeamAudit()))) {
                    businessUserLogDTO.setBeforeStatus(dictDataRespDTO.getLabel());
                }
            }
            businessUserLogDTO.setAppUserId(memberUserDO.getId());
            businessUserLogDTO.setUserId(SecurityFrameworkUtils.getLoginUserId());
            Integer userType = SecurityFrameworkUtils.getLoginUser().getUserType();
            if (UserTypeEnum.ADMIN.getValue().equals(userType)) {
                businessUserLogDTO.setContent(UserTypeEnum.ADMIN.getName() + "修改团长申请状态：" + businessUserLogDTO.getBeforeStatus() + "->" + businessUserLogDTO.getAfterStatus());
            }
            businessUserLogApi.addLog(businessUserLogDTO);
        }

        Integer oldTeamAudit = memberUserDO.getTeamAudit();

        memberUserDO.setTeamAudit(updateReqVO.getTeamAudit());

        if (TeamAuditEnum.PASSED.getCode().equals(updateReqVO.getTeamAudit())) {
            //团长审核通过
            memberUserDO.setIsTeam(1);
            //如果原来是商家，又申请团长，并且审核通过
            int isBusiness = memberUserDO.getIsBusiness();
            if(isBusiness==1) {
                //更新商家表的信息
                BusinessUserDTO businessUser = businessUserApi.getBusinessUserByUserId(memberUserDO.getId());
                //入驻商家--1,认证商家--2,商家团长--3,个人团长--4，保证金用户--5
                businessUser.setCreditId(3);
                businessUserApi.updateBusinessUserInfo(businessUser);
            }
            //后台可以指定商家团长的时间
            if (updateReqVO.getTeamOpenTime()!=null && updateReqVO.getTeamOverTime()!=null) {
                memberUserDO.setTeamOpenTime(updateReqVO.getTeamOpenTime());
                memberUserDO.setTeamOverTime(updateReqVO.getTeamOverTime());
            }
            //Optional.ofNullable(updateReqVO.getTeamOverTime())
            //如果是后台 审核 原来不是已审核的
//            else {
//                //个人团长
//                if (isBusiness == 2 && memberUserDO.getIsTeam() == 1) {
//                    if (memberUserDO.getTeamOpenTime() != null && !Objects.equals(oldTeamAudit, TeamAuditEnum.PASSED.getCode())) {
//                        LocalDate now = LocalDate.now();
//                        Integer profitYear = 1;
//                        //如果开启有收益时间，则设置过期时间
//                        WineConfigDTO wineConfigDTO = wineConfigApi.getWineConfigInfo();
//                        if (wineConfigDTO != null && wineConfigDTO.getIsOpenMonth() > 0 && wineConfigDTO.getFreeMonth() > 0) {
//                            profitYear = wineConfigDTO.getProfitYear();
//                        }
//                        LocalDate overTime = now.plusYears(profitYear);
//                        memberUserDO.setTeamOpenTime(now.atStartOfDay());
//                        memberUserDO.setTeamOverTime(overTime.atStartOfDay());
//                    }
//                }
//            }
        }
        memberUserMapper.updateById(memberUserDO);
    }
    /**
     * 信息审核
     * @param updateReqVO
     */
    @Override
    public void updateUserInfoAudit(MemberUserUpdateInfoAuditReqVO updateReqVO) {
        MemberUserDO memberUserDO = validateUserExists(updateReqVO.getUserId());
        if (memberUserDO != null) {
            memberUserDO.setAudit(updateReqVO.getAudit());
            memberUserMapper.updateById(memberUserDO);
        }
    }

    @Override
    public void updateUserDateTime(MemberUserDO bean) {
        memberUserMapper.updateById(bean);
    }

}